/**
 * 
 */
package com.edu.lawdoc.generator.field;

import java.io.File;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

import javax.sql.DataSource;

import com.baymax.validator.engine.ValidatorEngine;
import com.baymax.validator.engine.model.FieldRule;
import com.baymax.validator.engine.model.sub.NumericFieldRule;
import com.baymax.validator.engine.model.sub.StringRegexFieldRule;
import com.edu.lawdoc.generator.db.ModelGenerator;
import com.edu.lawdoc.generator.field.component.JavaCodeTemplateRender;
import com.edu.lawdoc.generator.field.component.entity.ColumnConstTemplateRender;
import com.edu.lawdoc.generator.field.kits.FileWriter;
import com.edu.lawdoc.generator.field.kits.TableMetaKit;
import com.edu.lawdoc.generator.field.meta.ColumnMeta;
import com.edu.lawdoc.generator.field.meta.MetaData;
import com.edu.lawdoc.generator.field.meta.TableMeta;
import com.edu.lawdoc.validator.ValueEnumRange;
import com.jfinal.template.Engine;


/**
 * @author huxiao
 *
 */
public class JavaCodeGenerator {

	private static List<JavaCodeTemplateRender> renderList = new ArrayList<> ();
	
	public JavaCodeGenerator(String mavenMainJavaPath, String outputRootPackage) {
		this.init(mavenMainJavaPath, outputRootPackage);
	}
	
	private void init(String mavenMainJavaPath,
			String outputRootPackage) {
		renderList.add(new ColumnConstTemplateRender(mavenMainJavaPath, outputRootPackage));
	}

	/**
	 * 初始化 enjoy 模板引擎
	 * @return
	 */
	public static Engine initEnjoy() {
		Engine ocoderEngine = Engine.create("ocoder");
		return ocoderEngine;
	}
	
	/**
	 * 将包路径转换成实际磁盘路径
	 * 获得src/main/java/路径
	 * @param packageUri
	 * @return
	 */
	public static String toPath(String mavenMainJavaPath, String packageUri) {
		return  mavenMainJavaPath + packageUri.replaceAll("\\.", File.separator);
	}
	
	/**
	 * 转换成骆驼命名方式
	 * @param name
	 * @return
	 */
	public static String formatHumpStyle(String name) {
		StringBuilder sb = new StringBuilder();
		Stack<Character> tmp = new Stack<Character>();
		char[] characters = name.toCharArray();
		for(char c : characters) {
			if(c == '_') {
				tmp.push(c);
				if(tmp.size() != 1) {
					return null;
				}
			}
			else {
				if(tmp.size() == 1) {
					sb.append(Character.toUpperCase(c));
					tmp.pop();
				}
				else {
					sb.append(Character.valueOf(c));
				}
			}
		}
		
		return Character.toUpperCase(characters[0]) + sb.substring(1);
	}


	/**
	 * 开始生成代码
	 * @param configFilePath
	 * @throws SQLException
	 */
	public void generate(String configFilePath) throws SQLException{
		List<String> exceptTables = new ArrayList<String> ();
		exceptTables.add("lp_global_seq");

		/**
		 * 从数据库中读取元数据配置
		 */
		DataSource dataSource = ModelGenerator.getDataSource(configFilePath);
		
		List<String> tables = TableMetaKit.getTables(dataSource, exceptTables);
		if(tables == null || tables.isEmpty()) {
			return;
		}

		Engine ve = initEnjoy();
		
		Map<String, TableMeta> tablesWithColumnMetaMapping = new HashMap<String, TableMeta>();
		Connection con = dataSource.getConnection(); //连接不能在循环里面，不然有可能占用很多的链接
		for(String tableName : tables) {			
			List<ColumnMeta> columnsMetaList = TableMetaKit.getColumnsMeta(con, tableName);
			if(columnsMetaList == null || columnsMetaList.isEmpty()) continue;
			
			TableMeta oTableMeta = new TableMeta();
			oTableMeta.setTableName(tableName);
			oTableMeta.setColumnMetaList(columnsMetaList);
			
			tablesWithColumnMetaMapping.put(tableName, oTableMeta);
		}
		
		MetaData metaData = new MetaData();
		metaData.setTablesWithColumnMetaMapping(tablesWithColumnMetaMapping);
		for(JavaCodeTemplateRender render : renderList) {
			render.render(ve, metaData);
		}

		String targetPackageName = ValueEnumRange.class.getPackage().getName();
		String className = ValueEnumRange.class.getSimpleName();
		generateValidatorConfig(tablesWithColumnMetaMapping, targetPackageName, className);
	}


	/**
	 * 生成字段校验相关的java类，此类用于数据校验，根据此类可以得到对应的属性，可以以json的形式反馈到前端
	 * 用于前端js校验
	 * @throws SQLException
	 */
	private static void generateValidatorConfig(Map<String, TableMeta> tablesWithColumnMetaMapping,
												String packageName, String classFileName) {
		List<FieldRule> list = new ArrayList<>();

		Iterator<Map.Entry<String, TableMeta>> it = tablesWithColumnMetaMapping.entrySet().iterator();
		while(it.hasNext()) {
			Map.Entry<String, TableMeta> entry = it.next();
			String tableName = entry.getKey();
			TableMeta tableMeta = entry.getValue();

			/**
			 * columnName: is_deleted, clazzName:String
			 * columnName: parent_id, clazzName:Long
			 * columnName: name, clazzName:String
			 * columnName: password, clazzName:String
			 * columnName: name_cn, clazzName:String
			 * columnName: user_number, clazzName:String
			 * columnName: is_admin, clazzName:String
			 * columnName: ticket, clazzName:String
			 * columnName: version, clazzName:Integer
			 */
			List<ColumnMeta> columnMetaList =  tableMeta.getColumnMetaList();
			for(ColumnMeta meta : columnMetaList) {
				String columnName = meta.getName();
				String clazzName = meta.getAbbreviationClass();

				if("id".equals(columnName) || "gmt_created".equals(columnName)
						|| "creator".equals(columnName) || "gmt_modified".equals(columnName)
						|| "modifier".equals(columnName) || "is_deleted".equals(columnName)
						|| "version".equals(columnName)) {
					continue;
				}

				if(String.class.getSimpleName().equals(clazzName)
						|| Date.class.getSimpleName().equals(clazzName)) {
					FieldRule rule = new StringRegexFieldRule();
					rule.setFieldKey(tableName + "." + columnName);
					rule.setStringRegexKey("any_string");
					rule.setStringLengthMin(1);
					rule.setStringLengthMax(128);
					rule.setStringCharset("utf8");
					rule.setType(ValidatorEngine.RuleType.string.name());
					list.add(rule);
				}
				else if(Integer.class.getSimpleName().equals(clazzName)
						|| Long.class.getSimpleName().equals(clazzName)) {
					FieldRule fr = new NumericFieldRule();
					fr.setFieldKey(tableName + "." + columnName);
					fr.setType(ValidatorEngine.RuleType.numeric.name());
					fr.setNumericMin(new BigInteger("0"));
					fr.setNumericMax(new BigInteger("999"));
					list.add(fr);
				}
			}
		}

		String valueRulesYmlPath = "validators/value_rules.yml";
		String newValueRulesYmlStr = ValidatorEngine.INSTANCE.generateDefaultYml(valueRulesYmlPath, list);
		System.out.println(newValueRulesYmlStr);

		String targetClassesPath = JavaCodeGenerator.class.getProtectionDomain().getCodeSource().getLocation().getPath();
		String srcResourcesPath = targetClassesPath + "../../src/main/resources/validators";

		FileWriter.backupAndWrite(srcResourcesPath, "value_rules", "yml", newValueRulesYmlStr);

		ValidatorEngine.INSTANCE.init(valueRulesYmlPath);
		String sourceFormated = ValidatorEngine.INSTANCE.generateJavaEnumCode(packageName);

		String srcJavaPath = targetClassesPath + "../../src/main/java";
		String packagePath = File.separator + packageName.replaceAll("\\.", File.separator);
		FileWriter.write(srcJavaPath + packagePath, classFileName, "java", sourceFormated);
	}


	public static void main(String[] args){
		JavaCodeGenerator oJavaCodeGenerator = new JavaCodeGenerator(
				CodePath.mavenMainJavaPath,
				CodePath.outputRootPackage);
		try {
			oJavaCodeGenerator.generate(CodePath.getConfigFilePath());
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
